/** create by liuhua at 2019年05月28日 上午10:32:24 **/
package com.star.aries.utils;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.star.aries.intf.CacheType;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class MemoryCacheUtil {
  
  private static Cache<CacheType, Cache<Object, Object>> cache = CacheBuilder.newBuilder().maximumSize(1000).build();
  
  public static <T, R> R get(CacheType cacheType, T key, boolean fromCache, Function<T, R> fn, R defaultValue) {
    if(null == key) {
      return defaultValue;
    }
    R r = get(cacheType, key, fromCache);
    if(null == r) {
      r = fn.apply(key);
      put(cacheType, key, r);
    }
    return r;
  }
  
  public static <T, R, A> R get(CacheType cacheType, T key, boolean fromCache, A a, Function<A, R> fn, R defaultValue) {
    if(null == key) {
      return defaultValue;
    }
    R r = get(cacheType, key, fromCache);
    if(null == r) {
      r = fn.apply(a);
      put(cacheType, key, r);
    }
    return r;
  }
  
  public static <T> void put(CacheType cacheType, Object key, T object) {
    put(cacheType, cacheType.getTime(), key, object);
  }
  
  public static <T> void put(CacheType cacheType, long timeMillis, Object key, T object) {
    if(null == key || null == object) {
      return;
    }
    try {
      Cache<Object, Object> map = cache.get(cacheType, new Callable<Cache<Object, Object>>() {
        @Override
        public Cache<Object, Object> call() throws Exception {
          return CacheBuilder.newBuilder().expireAfterWrite(timeMillis, TimeUnit.MILLISECONDS).maximumSize(cacheType.getSize()).build();
        }
      });
      map.put(key, object);
    } catch (Exception e) {
      log.error("", e);
    }
  }

  @SuppressWarnings("unchecked")
  public static <T> T get(CacheType cacheType, Object key, boolean fromCache) {
    if(null == key || ! fromCache) {
      return null;
    }
    try {
      Cache<Object, Object> map = cache.getIfPresent(cacheType);
      if (null == map || map.size() == 0) {
        return null;
      }
      Object object = map.getIfPresent(key);
      return (T) object;
    } catch (Exception e) {
      log.warn("", e);
    }
    return null;
  }
}
